//封装 axios 请求模块
import axios from "axios";
// import jsonBig from "json-bigint";
import store from "@/store";
import router from "@/router";
import jsonBig from "json-bigint";

// axios.create 方法：复制一个 axios
const request = axios.create({
  baseURL: "http://toutiao.itheima.net/", // 基础路径
  // baseURL: "http://192.168.11.34:8000",
  // transformResponse允许自定义原始的响应数据(字符串)
  // 自定义后端返回的原始数据
  // data就是后端返回的原始数据，也就是JSON格式的字符串
  transformResponse: [
    function (data) {
      try {
        // 如果转换成功就返回转换的数据结果
        // jsonBig可以处理数据超出JavaScript安全范围的问题
        // jsonBig.stringify()把JavaScript对象转为JSON格式的字符串
        return jsonBig.parse(data); // 把JSON格式的字符串转为JavaScript对象
      } catch (err) {
        // 如果转换失败就包装为统一数据格式并返回
        return data;
      }
      // axios默认会在内部这样处理后端返回的数据
      // return JSON.parse(data)
    },
  ],
});

// 请求拦截器
request.interceptors.request.use(
  function (config) {
    // 请求发起会经过这里
    // config就是本次请求的配置对象
    const { user } = store.state;
    if (user && user.token) {
      config.headers.Authorization = `Bearer ${user.token}`;
    }
    //这里务必要返回config配置对象，否则请求就停在这里出不去了
    return config;
  },
  function (error) {
    // 如果请求出错了(还没有发出去)会进入这里
    return Promise.reject(error);
  }
);

// 响应拦截器
request.interceptors.response.use(
  // 第一个函数就是正常响应的时候要调用的函数
  // 响应成功进入第1个函数
  // 该函数的参数是响应对象
  function (response) {
    return response;
  },
  // 响应失败进入第2个函数，该函数的参数是错误对象
  // 第二个函数是响应出错的时候会执行的函数
  async function (error) {
    // 如果响应码是401则请求获取新的 token
    // 响应拦截器中的error就是那个响应的错误对象
    // 下面的if判断就是判断 错误的状态码是不是 401，如果是401代表就是token过期了
    if (error.response && error.response.status === 401) {
      // 校验是否有 refresh_token
      // 获取到Vuex中保存的user用户数据，在user用户数据中包含了过期的token和refresh_token
      const user = store.state.user;
      // 如果user不存在或者user里面没有refresh_token
      if (!user || !user.refresh_token) {
        // 跳转到登录页面
        router.push("/login");
        // 代码不要往后执行了
        return;
      }
      // 如果有refresh_token则请求获取新的token
      try {
        // 当请求刷新用户token的接口之后，接口返回的数据中就包含了最新的token
        const res = await axios({
          method: "PUT",
          url: "http://toutiao.itheima.net/v1_0/authorizations",
          // url:' http://192.168.11.34:8000',
          headers: {
            Authorization: `Bearer ${user.refresh_token}`,
          },
        });
        // 如果获取成功则把新的token更新到容器中
        console.log("刷新 token  成功", res);
        store.commit("setUser", {
          token: res.data.data.token, // 最新获取的可用token
          refresh_token: user.refresh_token, // 还是原来的refresh_token
        });
        // 把之前失败的用户请求继续发出去
        // config 是一个对象，其中包含本次失败请求相关的那些配置信息，例如 url、method都有
        // return把request的请求结果继续返回给发请求的具体位置
        // error.config就是之前发生错误的那次请求的配置对象
        // 按照之前错误的那次请求的配置，重新请求一次
        return request(error.config);
      } catch (err) {
        // 如果获取失败，直接跳转 登录页
        console.log("请求刷新 token 失败", err);
        router.push("/login");
      }
    }
    return Promise.reject(error);
  }
);

export default request;
